package lockDemo;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Ajie
 * @date 8/31/21
 * @function 手写生产者消费者模式 阻塞队列方式

LinkedBlockingDeque 适用于多线程。生产、消费，并发。外部无须再加锁。
内部 put/take 已经有锁了。
 */
public class ProducerAndConsumer_BlockingQueue {
    private BlockingQueue<Toy> blockingDeque = new LinkedBlockingDeque<>(50);

    private static AtomicInteger countProut = new AtomicInteger();//生产的总数 ，只是用来计数
    private static AtomicInteger countConsumer = new AtomicInteger();//消费的总数 ，只是用来计数

    public static void main(String[] args) {
        ProducerAndConsumer_BlockingQueue producerAndConsumer = new ProducerAndConsumer_BlockingQueue();

        new Thread(producerAndConsumer.new Producer()).start();
        new Thread(producerAndConsumer.new Producer()).start();
        new Thread(producerAndConsumer.new Consumer()).start();
        new Thread(producerAndConsumer.new Consumer()).start();
        new Thread(producerAndConsumer.new Consumer()).start();
        new Thread(producerAndConsumer.new Consumer()).start();
        new Thread(producerAndConsumer.new Producer()).start();
        new Thread(producerAndConsumer.new Producer()).start();
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            int i=0;
            while (true) {
                if (countProut.get()>=1000000){
                    System.out.println("product over---"+countProut.get());
                    return;
                }
                Toy toy = new Toy((++i) + "");
                try {

                    blockingDeque.put(toy);
                    System.out.println( "生产者" + Thread.currentThread().getName() + " 生产玩具" + toy.getName()+"     ------计数："+countProut.getAndIncrement());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    Toy toy = blockingDeque.take();
                    countConsumer.getAndIncrement();
                    System.err.println("消费者" + Thread.currentThread().getName() + " 消费玩具" + toy.getName()+"  消费总数："+countConsumer.get());

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Toy {
        private String name;

        public Toy(String name) {
            this.name = name;
        }
        public String getName() {
            return "toy " + name;
        }
    }
}